package com.cx.common.utils;

import org.codehaus.jackson.Version;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
import org.codehaus.jackson.map.module.SimpleModule;
import org.codehaus.jackson.map.type.ArrayType;
import org.codehaus.jackson.map.type.TypeFactory;
import org.codehaus.jackson.type.JavaType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MessageFormatter;

import java.io.StringWriter;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 *
 * JSON 转换相关的工具类 注意,Map的Key只能为简单类型 ,不可采用复杂类型.
 *
 * @Author:cxy
 * @Date:2019/10/24 15:11
 */
public final class JsonUtils {

	private JsonUtils() {
		throw new IllegalAccessError("该类不允许实例化");
	}

	private static final Logger log = LoggerFactory.getLogger(JsonUtils.class);

	private static final ObjectMapper mapper;

	private static final ObjectMapper ignoreNullMapper;

	static {
		mapper = new ObjectMapper();
		mapper.enable(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
		SimpleModule module = new SimpleModule("Custom", new Version(1, 0, 0, null));
		module.addDeserializer(int[].class, new IntArrayDeserializer());
		module.addSerializer(Double.class, DoubleSerializer.INSTANCE);
		module.addSerializer(Double.TYPE, DoubleSerializer.INSTANCE);
		mapper.registerModule(module);

		ignoreNullMapper = new ObjectMapper();
		ignoreNullMapper.setSerializationInclusion(Inclusion.NON_NULL);
		ignoreNullMapper.configure(SerializationConfig.Feature.WRITE_NULL_MAP_VALUES, false);

		ignoreNullMapper.enable(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
		SimpleModule moduleNull = new SimpleModule("Custom", new Version(1, 0, 0, null));
		moduleNull.addDeserializer(int[].class, new IntArrayDeserializer());
		moduleNull.addSerializer(Double.class, DoubleSerializer.INSTANCE);
		moduleNull.addSerializer(Double.TYPE, DoubleSerializer.INSTANCE);
		ignoreNullMapper.registerModule(moduleNull);

	}

	/**
	 * 将对象转换为 JSON 的字符串格式
	 * 
	 * @param object
	 * @return
	 */
	public static String object2String(Object object) {
		return object2String(object, false);
	}

	public static String object2String(Object object, boolean prettyFormat) {
		StringWriter writer = new StringWriter();
		try {
			if (prettyFormat) {
				mapper.writerWithDefaultPrettyPrinter().writeValue(writer, object);
			} else {
				mapper.writeValue(writer, object);
			}
		} catch (Exception e) {
			log.error("将 object 转换为 json 字符串时发生异常:{}", e);
			return null;
		}
		return writer.toString();
	}

	public static String object2StringIgnoreNullField(Object object) {
		return object2StringIgnoreNullField(object, false);
	}

	public static String object2StringIgnoreNullField(Object object, boolean prettyFormat) {
		StringWriter writer = new StringWriter();
		try {
			if (prettyFormat) {
				ignoreNullMapper.writerWithDefaultPrettyPrinter().writeValue(writer, object);
			} else {
				ignoreNullMapper.writeValue(writer, object);
			}
		} catch (Exception e) {
			log.error("将 object 转换为 json 字符串时发生异常:{}", e);
			return null;
		}
		return writer.toString();
	}

	/**
	 * 将 map 转换为 JSON 的字符串格式
	 * 
	 * @param map
	 * @return
	 */
	public static String map2String(Map<?, ?> map) {
		StringWriter writer = new StringWriter();
		try {
			mapper.writeValue(writer, map);
		} catch (Exception e) {
			log.error("将 map 转换为 json 字符串时发生异常:{}", e);
			return null;
		}
		return writer.toString();
	}

	/**
	 * 将 JSON 格式的字符串转换为 map
	 * 
	 * @param content
	 * @return
	 */
	public static Map<String, Object> string2Map(String content) {
		JavaType type = TypeFactory.defaultInstance().constructMapType(HashMap.class, String.class, Object.class);
		// JavaType type = TypeFactory.mapType(HashMap.class, String.class,
		// Object.class);
		try {
			return mapper.readValue(content, type);
		} catch (Exception e) {
			FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为Map时出现异常", content);
			log.error(message.getMessage(), e);
			throw new RuntimeException(message.getMessage(), e);
		}
	}

	/**
	 * 将 JSON 格式的字符串转换为 map
	 * 
	 * @param content
	 * @return
	 */
	public static Map<String, Integer[]> string2MapInts(String content) {
		JavaType type = TypeFactory.defaultInstance().constructMapType(HashMap.class, String.class, Integer[].class);
		// JavaType type = TypeFactory.mapType(HashMap.class, String.class,
		// Object.class);
		try {
			return mapper.readValue(content, type);
		} catch (Exception e) {
			FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为Map时出现异常", content);
			log.error(message.getMessage(), e);
			throw new RuntimeException(message.getMessage(), e);
		}
	}

	public static void main(String[] args) {

		Map<String, Integer[]> map = new HashMap<String, Integer[]>();
		Integer[] arr = ArrayUtil.array(1, 2, 3);
		map.put("a", arr);
		map.put("b", arr);
		String object2String = JsonUtils.object2String(map);

		Map<String, Integer[]> string2Map = JsonUtils.string2Map(object2String, String.class, Integer[].class);
		System.err.println(JsonUtils.object2String(string2Map));
	}

	/**
	 * 将 JSON 格式的字符串转换为 map
	 * 
	 * @param content
	 * @return
	 */
	public static Map<String, String> string2MapString(String content) {
		JavaType type = TypeFactory.defaultInstance().constructMapType(HashMap.class, String.class, String.class);
		// JavaType type = TypeFactory.mapType(HashMap.class, String.class,
		// Object.class);
		try {
			return mapper.readValue(content, type);
		} catch (Exception e) {
			FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为Map时出现异常", content);
			log.error(message.getMessage(), e);
			throw new RuntimeException(message.getMessage(), e);
		}
	}

	/**
	 * 将 JSON 格式的字符串转换为数组
	 * 
	 * @param         <T>
	 * @param content 字符串
	 * @param clz     数组类型
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T[] string2Array(String content, Class<T> clz) {
		JavaType type = ArrayType.construct(TypeFactory.defaultInstance().constructType(clz), null, null);
		try {
			return (T[]) mapper.readValue(content, type);
		} catch (Exception e) {
			FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为数组时出现异常", content);
			log.error(message.getMessage(), e);
			throw new RuntimeException(message.getMessage(), e);
		}
	}

	/**
	 * 将 JSON 格式的字符串转换为对象
	 * 
	 * @param         <T>
	 * @param content 字符串
	 * @param clz     对象类型
	 * @return
	 */
	public static <T> T string2Object(String content, Class<T> clz) {
		JavaType type = TypeFactory.defaultInstance().constructType(clz);
		return string2Object(content, type);
	}

	@SuppressWarnings("unchecked")
	public static <T> T string2Object(String content, JavaType type) {
		try {
			return (T) mapper.readValue(content, type);
		} catch (Exception e) {
			FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为对象[{}]时出现异常",
					new Object[] { content, type, e });
			log.error(message.getMessage(), e);
			throw new RuntimeException(message.getMessage(), e);
		}
	}

	/**
	 * 将 JSON 格式的字符串转换为集合
	 * 
	 * @param                <T>
	 * @param content        字符串
	 * @param collectionType 集合类型
	 * @param elementType    元素类型
	 * @return
	 */
	public static <C extends Collection<E>, E> C string2Collection(String content, Class<C> collectionType,
			Class<E> elementType) {
		try {
			JavaType type = TypeFactory.defaultInstance().constructCollectionType(collectionType, elementType);
			// JavaType type = TypeFactory.collectionType(collectionType,
			// elementType);
			return mapper.readValue(content, type);
		} catch (Exception e) {
			FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为集合[{}]时出现异常",
					new Object[] { content, collectionType.getSimpleName(), e });
			log.error(message.getMessage(), e);
			throw new RuntimeException(message.getMessage(), e);
		}
	}

	@SuppressWarnings("unchecked")
	public static <K, V> Map<K, V> string2Map(String content, Class<K> keyType, Class<V> valueType) {
		JavaType type = TypeFactory.defaultInstance().constructMapType(HashMap.class, keyType, valueType);
		try {
			return (Map<K, V>) mapper.readValue(content, type);
		} catch (Exception e) {
			FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为Map时出现异常", content);
			log.error(message.getMessage(), e);
			throw new RuntimeException(message.getMessage(), e);
		}
	}

	@SuppressWarnings("unchecked")
	public static <K, V> Map<K, V> string2LinkedHashMap(String content, Class<K> keyType, Class<V> valueType) {
		JavaType type = TypeFactory.defaultInstance().constructMapType(LinkedHashMap.class, keyType, valueType);
		try {
			return (Map<K, V>) mapper.readValue(content, type);
		} catch (Exception e) {
			FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为Map时出现异常", content);
			log.error(message.getMessage(), e);
			throw new RuntimeException(message.getMessage(), e);
		}
	}

	public static Map<?, ?> string2Map(String content, JavaType keyType, JavaType valueType) {
		JavaType type = TypeFactory.defaultInstance().constructMapType(HashMap.class, keyType, valueType);
		try {
			return (Map<?, ?>) mapper.readValue(content, type);
		} catch (Exception e) {
			FormattingTuple message = MessageFormatter.format("将字符串[{}]转换为Map时出现异常", content);
			log.error(message.getMessage(), e);
			throw new RuntimeException(message.getMessage(), e);
		}
	}

}
